package cn.remex.wechat.config;

import cn.remex.RemexConstants;
import cn.remex.core.exception.ServiceCode;
import cn.remex.core.util.Assert;
import cn.remex.core.util.JsonHelper;
import cn.remex.core.util.Judgment;
import cn.remex.core.util.MapHelper;
import cn.remex.db.Database;
import cn.remex.db.model.SysUser;
import cn.remex.db.sql.SqlColumn;
import cn.remex.db.sql.WhereRuleOper;
import cn.remex.wechat.WeChat;
import cn.remex.wechat.WeChatService;
import cn.remex.wechat.beans.WeChatAccessToken;
import cn.remex.wechat.beans.WeChatResult;
import cn.remex.wechat.beans.WeChatUserInfo;
import cn.remex.wechat.beans.WeChatUserOpenIdList;
import cn.remex.wechat.beans.messages.CustomMsg;
import cn.remex.wechat.beans.messages.QyMsgTextData;
import cn.remex.wechat.beans.messages.TemplateMessage;
import cn.remex.wechat.beans.messages.WeChatMessageResult;
import cn.remex.wechat.beans.paymch.WeChatUnifiedorder;
import cn.remex.wechat.beans.paymch.WeChatUnifiedorderResult;
import cn.remex.wechat.beans.qy.WeChatQyUserInfo;
import cn.remex.wechat.beans.ticket.JsapiTicket;
import cn.remex.wechat.beans.ticket.WeChatQrcodeTicketResult;
import cn.remex.wechat.models.WeChatAppConfig;
import cn.remex.wechat.models.WeChatToken;
import cn.remex.wechat.models.WeChatUser;
import cn.remex.wechat.utils.*;
import com.fasterxml.jackson.databind.JsonNode;

import java.io.File;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;

import static cn.remex.wechat.config.WeChatAppType.qy;
import static cn.remex.wechat.models.WeChatToken.WeChatTokenType.accessToken;
import static cn.remex.wechat.models.WeChatToken.WeChatTokenType.jsapiToken;
import static cn.remex.wechat.utils.WeChatUtils.WeChatApi.*;

/**
 * 名称：
 * 缩写：
 * 用途：
 * Created by yangy on 2016/8/23 0023.
 */
public class WeChatApp/* implements InitializingBean */{


	WeChatAppConfig config;
	private Map<String, String> stateRedirects;
	private Map<String, String> wxClickEventMsgs;
	public WeChatApp(WeChatAppConfig config) {
		this.config = config;
		stateRedirects = JsonHelper.toJavaObject(config.getStateRedirects(), HashMap.class);
		wxClickEventMsgs = JsonHelper.toJavaObject(config.getWxClickEventMsgs(), HashMap.class);

		//处理一下
	}

	public String key(){
		return getConfig().getAppName();
	}

	//-----------------------------------------------------//
	//access_token是公众号的全局唯一票据，公众号调用各接口时都需使用access_token
	/*
	 * 获取access token
	 *
	 * access_token是公众号的全局唯一票据，公众号调用各接口时都需使用access_token。
	 * 开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。
	 * access_token的有效期目前为2个小时，需定时刷新，重复获取将导致上次获取的access_token失效。
	 */
	public String getAccess_token() {
		//数据库获取token
		WeChatToken weChatToken = Database.createDbCvo(WeChatToken.class)
				.filterBy(WeChatToken::getValid, WhereRuleOper.equal, "true")
				.filterBy(WeChatToken::getType, WhereRuleOper.equal, accessToken)
				.filterBy(WeChatToken::getAgentid, WhereRuleOper.equal, config.getAgentid())
				.filterBy(WeChatToken::getAppid, WhereRuleOper.equal, config.getAppid()).ready().queryBean();
		LocalDateTime localDateTimenow = LocalDateTime.now();
		if (!Judgment.nullOrBlank(weChatToken)) { // 如果不为空 则则说明数据库中有
			LocalDateTime localDateTime = LocalDateTime.parse(weChatToken.getAccessTime()); //  token存入的时间
			if (localDateTimenow.until(localDateTime, ChronoUnit.SECONDS) > -7000) { // 判断token是否失效 2小时失效
				return weChatToken.getAccessToken();  //返回token
			}
			weChatToken.setValid(false);
			Database.getSession().store(weChatToken); //失效 做好标志位
		}
		//若数据库中没有token 或者刚刚删除， 则去获取新的token 存入
		Assert.notNullAndEmpty(config.getAppid(), ServiceCode.ERROR, "config.getAppid() 不能为空~！");
		Assert.notNullAndEmpty(config.getSecret(), ServiceCode.ERROR, "config.getSecret() 不能为空~！");

		WeChatAccessToken weChectAccessToken = WeChatUtils.invokeApiReturnBean(this, "", WeChatAccessToken.class, access_token, config.getAppid(), config.getSecret());

		WeChatToken weChatToken1 = new WeChatToken();
		weChatToken1.setAccessToken(weChectAccessToken.getAccess_token());
		weChatToken1.setAccessTime(localDateTimenow.toString());
		weChatToken1.setAppid(config.getAppid());
		weChatToken1.setAgentid(config.getAgentid());
		weChatToken1.setType(accessToken);
		weChatToken1.setValid(true);
		Database.getSession().store(weChatToken1);
		return weChectAccessToken.getAccess_token();
	}
	// jsapi_ticket 是公众号的全局唯一js调用票据，公众号调用各jsapi接口时都需使用
	/*
	 * 生成签名之前必须先了解一下jsapi_ticket，jsapi_ticket是公众号用于调用微信JS接口的临时票据。
	 * 正常情况下，jsapi_ticket的有效期为7200秒，通过access_token来获取。
	 * 由于获取jsapi_ticket的api调用次数非常有限，频繁刷新jsapi_ticket会导致api调用受限，影响自身业务，
	 * 开发者必须在自己的服务全局缓存jsapi_ticket 。
	 */
	public String getJsapi_ticket() {
		//数据库获取token
		WeChatToken weChatToken = Database.createDbCvo(WeChatToken.class)
				.filterBy(WeChatToken::getValid, WhereRuleOper.equal, "true")
				.filterBy(WeChatToken::getType, WhereRuleOper.equal, jsapiToken)
				.filterBy(WeChatToken::getAgentid, WhereRuleOper.equal, config.getAgentid())
				.filterBy(WeChatToken::getAppid, WhereRuleOper.equal, config.getAppid()).ready().queryBean();
		LocalDateTime localDateTimenow = LocalDateTime.now();
		if (!Judgment.nullOrBlank(weChatToken)) { // 如果不为空 则则说明数据库中有
			LocalDateTime localDateTime = LocalDateTime.parse(weChatToken.getAccessTime()); //  ticket存入的时间
			if (localDateTimenow.until(localDateTime, ChronoUnit.SECONDS) > -7000) { // 判断ticket是否失效  2小时失效
				return weChatToken.getTicket();  //返回 jsapi ticket
			}
			weChatToken.setValid(false);
			Database.getSession().store(weChatToken); //失效 做好标志位
		}
		//若数据库中没有token 或者刚刚删除， 则去获取新的token 存入
		WeChatAccessToken WeChatAccessToken = WeChatUtils.invokeApiReturnBean(this, "", WeChatAccessToken.class, jsapi_ticket, getAccess_token());

		WeChatToken weChatToken1 = new WeChatToken();
		weChatToken1.setTicket(WeChatAccessToken.getTicket());
		weChatToken1.setAccessTime(localDateTimenow.toString());
		weChatToken1.setAppid(config.getAppid());
		weChatToken1.setAgentid(config.getAgentid());
		weChatToken1.setType(jsapiToken);
		weChatToken1.setValid(true);
		Database.getSession().store(weChatToken1);
		return WeChatAccessToken.getTicket();
	}

	/*
	 * 微信 生成 永久字符串二维码_限定场景的二维码
	 * @param scene_str 二维码场景内容
	 */
	public WeChatQrcodeTicketResult qrcode_create_limitScene(String scene_str){
		/**
		 * 、为了满足用户渠道推广分析和用户帐号绑定等场景的需要，公众平台提供了生成带参数二维码的接口。使用该接口可以获得多个带不同场景值的二维码，用户扫描后，公众号可以接收到事件推送。
		 * 1、临时二维码，是有过期时间的，最长可以设置为在二维码生成后的30天（即2592000秒）后过期，但能够生成较多数量。临时二维码主要用于帐号绑定等不要求二维码永久保存的业务场景
		 * 2、永久二维码，是无过期时间的，但数量较少（目前为最多10万个）。永久二维码主要用于适用于帐号绑定、用户来源统计等场景。
		 * 用户扫描带场景值二维码时，可能推送以下两种事件：
		 * 如果用户还未关注公众号，则用户可以关注公众号，关注后微信会将带场景值关注事件推送给开发者。
		 * 如果用户已经关注公众号，在用户扫描后会自动进入会话，微信也会将带场景值扫描事件推送给开发者。
		 */
		RemexConstants.logger.info("微信二维码内容："+scene_str);
		Assert.notNullAndEmpty(scene_str, ServiceCode.WEIXIN_ARGS_INVALID, "微信二维码内容！");

		String json =  "{\"action_name\": \"QR_LIMIT_STR_SCENE\", \"action_info\": {\"scene\": {\"scene_str\": \""+scene_str+"\"}}}";
		WeChatQrcodeTicketResult weChatQrcodeTicketResult = WeChatUtils.invokeApiReturnBean(this, json, WeChatQrcodeTicketResult.class, qrcode_create, getAccess_token());

		return weChatQrcodeTicketResult;
	}
	/*
	 *  微信生成 临时二维码——临时场景的二维码
	 * @param scene_id 只能是int的整数
	 * @param expire_seconds 有效时间。 默认200s
	 */
	public WeChatQrcodeTicketResult qrcode_create_scene(String scene_id, String expire_seconds){
		/**
		 * 、为了满足用户渠道推广分析和用户帐号绑定等场景的需要，公众平台提供了生成带参数二维码的接口。使用该接口可以获得多个带不同场景值的二维码，用户扫描后，公众号可以接收到事件推送。
		 * 1、临时二维码，是有过期时间的，最长可以设置为在二维码生成后的30天（即2592000秒）后过期，但能够生成较多数量。临时二维码主要用于帐号绑定等不要求二维码永久保存的业务场景
		 * 2、永久二维码，是无过期时间的，但数量较少（目前为最多10万个）。永久二维码主要用于适用于帐号绑定、用户来源统计等场景。
		 * 用户扫描带场景值二维码时，可能推送以下两种事件：
		 * 如果用户还未关注公众号，则用户可以关注公众号，关注后微信会将带场景值关注事件推送给开发者。
		 * 如果用户已经关注公众号，在用户扫描后会自动进入会话，微信也会将带场景值扫描事件推送给开发者。
		 */
		Assert.notNullAndEmpty(scene_id, ServiceCode.WEIXIN_ARGS_INVALID,"微信二维码内容！");
		expire_seconds = Judgment.nullOrBlank(expire_seconds) ? "200" : expire_seconds;

		String json =  "{\"action_name\": \"QR_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": \""+scene_id+"\"}}}";
		WeChatQrcodeTicketResult weChatQrcodeTicketResult = WeChatUtils.invokeApiReturnBean(this, json, WeChatQrcodeTicketResult.class, qrcode_create, getAccess_token());


		return weChatQrcodeTicketResult;
	}
	public String showqrcode(String qr_tiket){
		return obtainApiUrl(showqrcode, qr_tiket);
	}
	public String oauth2_authorize(String redirectUrl,String state){
		return obtainApiUrl(oauth2_authorize, config.getAppid(), redirectUrl, state);
	}

	/*
	 *  微信 统一下单接口
	 */
	public WeChatUnifiedorderResult payUnifiedorder(WeChatUnifiedorder weChatUnifiedorder){
		Map<String, String> map = MapHelper.objectToFlat(weChatUnifiedorder);
		if( !Judgment.nullOrBlank(config.getKey())){
			String sign = Signature.generateSign(map, config.getKey());
			weChatUnifiedorder.setSign(sign);
		}
		return WeChatUtils.invokeApiReturnXml(this, weChatUnifiedorder, WeChatUnifiedorderResult.class, payUnifiedorder);
	}
	public WeChatMessageResult templatMsgSend(TemplateMessage templateMessage){
		return WeChatUtils.invokeApiReturnBean(this, JsonHelper.toJsonString(templateMessage), WeChatMessageResult.class, templatMsgSend, getAccess_token());
	}
	public WeChatMessageResult customMsgSend(CustomMsg customMsg){
		return WeChatUtils.invokeApiReturnBean(this, JsonHelper.toJsonString(customMsg), WeChatMessageResult.class, customMsgSend, getAccess_token());
	}
	/*
	 * 创建菜单
	 */
	public WeChatResult menuCreate(String menusJson){
		menusJson.replaceAll("\\$\\{appid\\}",config.getAppid());
//		String json = JsonHelper.toJsonString(MapHelper.toMap("button",menuButtons==null? JsonHelper.toJsonNode(config.getMenus()):null));
		WeChatResult WeChatResult = WeChatUtils.invokeApiReturnBean(this, menusJson, WeChatResult.class, menu_create, getAccess_token(), config.getAgentid());
		return WeChatResult;
	}
	public String menuGet(){
		JsonNode jsonRoot = WeChatUtils.invokeApiReturnJson(this, "", menu_get, getAccess_token(), config.getAgentid());
		return jsonRoot.toString();
	}
	public String obtainOpenidByCode(String code) {
		//企业号和服务号的openid获取机制不同
		String openid,userid;
		if (config.getType() == WeChatAppType.qy) {
			WeChatQyUserInfo weChatQyUserInfo = getuserinfo(code);
			userid = weChatQyUserInfo.getUserId();
			openid = weChatQyUserInfo.getOpenId();
			if (!Judgment.nullOrBlank(userid)) {
				openid = openIdFromUserId(userid);//"o1dzwv1e8Nl1Eq_OA3jvBScf0tAg";}
				SysUser sysUser = Database.select(SysUser.class)
						.filterBy(SysUser::getStaffNo, WhereRuleOper.equal, userid)
						.withBase().rowCount(1)
						.execute().obtainBean();
				if (null != sysUser) {
					WeChatService.bindUser(config.getAppid(), config.getAgentid(), openid, sysUser);
				}
			}
		}else {
			JsonNode jsonRoot = WeChatUtils.invokeApiReturnJson(this, "", oauth2_access_token, config.getAppid(), config.getSecret(), code);
			openid = JsonHelper.readString(jsonRoot,"openid");
		}
		return openid;
	}
	public WeChatQyUserInfo getuserinfo(String code) {
		Assert.isTrue(config.getType()==qy,ServiceCode.WEIXIN_CONFIG_ERROR,"只有企业号才能调用此接口：getuserinfo");

		JsonNode jsonRoot = WeChatUtils.invokeApiReturnJson(this, "", getuserinfo, getAccess_token(),  code);

		WeChatQyUserInfo userInfo = new WeChatQyUserInfo();
		userInfo.setOpenId(JsonHelper.readString(jsonRoot,"OpenId"));
		userInfo.setUserId(JsonHelper.readString(jsonRoot,"UserId"));
		return userInfo;//微信内部大小写混乱，没办法这里和他统一
	}
	public WeChatQyUserInfo getLoginInfo(String code) {
		Assert.isTrue(config.getType()==qy,ServiceCode.WEIXIN_CONFIG_ERROR,"只有企业号才能调用此接口：getLoginInfo");

		JsonNode jsonRoot = WeChatUtils.invokeApiReturnJson(this, "", get_login_info, getAccess_token(),  code);

		WeChatQyUserInfo userInfo = new WeChatQyUserInfo();
		userInfo.setOpenId(JsonHelper.readString(jsonRoot,"OpenId"));
		userInfo.setUserId(JsonHelper.readString(jsonRoot,"UserId"));
		return userInfo;//微信内部大小写混乱，没办法这里和他统一
	}
	public SysUser obtainSysUserByOpenId(String openid) {
		SysUser curSysUser = null;

		if(!Judgment.nullOrBlank(openid)){
			WeChatUser dbWeChatUser = Database.select(WeChatUser.class)
					.filterBy(WeChatUser::getOpenid, WhereRuleOper.equal, openid)
					.withBase().withModel(WeChatUser::getSysUser, SqlColumn::withBase).rowCount(1)
					.execute().obtainBean();
			if (dbWeChatUser != null && dbWeChatUser.getSysUser() != null) {
				curSysUser = dbWeChatUser.getSysUser();
			}
		}

		return curSysUser;
	}

	public void media_get(String mediaId, Consumer<InputStream> consumer){
		 WeChatUtils.invokeApiHandleStream(this,"",consumer,media_get, getAccess_token(),mediaId);
	}

	public String img_tmp_add(File imgFile){
		Map<String, Object> fileMap = new HashMap<>();
		fileMap.put("media", imgFile);
		JsonNode node = WeChatUtils.invokeApiMultipartReturnJson(this, fileMap, media_tmp_add, getAccess_token(), "image");
		return node.findPath("media_id").asText();
	}

	/*
	 * 在关注者与公众号产生消息交互后，
	 * 公众号可获得关注者的OpenID
	 * （加密后的微信号，每个用户对每个公众号的OpenID是唯一的。对于不同公众号，同一用户的openid不同）。
	 * 公众号可通过本接口来根据OpenID获取用户基本信息，包括昵称、头像、性别、所在城市、语言和关注时间。
	 */
	public WeChatUserInfo userInfo(String openId) {
		//企业号功能不全,临时用一下 TODO
		if(config.getType()==qy){
			WeChatUserInfo info = new WeChatUserInfo();
			info.setOpenid(openId);
			return info;
		}

		Assert.notNullAndEmpty(openId, ServiceCode.OPENID_INVALID, "用户openId 不能为空~！");

		WeChatUserInfo weChatUserInfo = WeChatUtils.invokeApiReturnBean(this, "", WeChatUserInfo.class, userInfo, getAccess_token(), openId);
		String nickname = weChatUserInfo.getNickname();
		if (!Judgment.nullOrBlank(nickname)) { // 只 支持 unic表情，字符 删除其他
			weChatUserInfo.setNickname(nickname.replaceAll("[^\\w\u4e00-\u9fa5]", ""));
		}
		return "0".equals(weChatUserInfo.getSubscribe()) ? null : weChatUserInfo;
	}
	public String openIdFromUserId(String userId) {
		Assert.isTrue(config.getType()==qy,ServiceCode.WEIXIN_CONFIG_ERROR,"只有企业号才能调用此接口：userId to openId");

		String json = String.format("{\"userid\": \"%s\"}",userId);
		JsonNode jsonRoot = WeChatUtils.invokeApiReturnJson(this, json, userid_to_openid, getAccess_token());

		Assert.nullOrEmpty(JsonHelper.readString(jsonRoot, "errcode"),ServiceCode.FAIL,"企业中转换userId to openId 失败");
		return JsonHelper.readString(jsonRoot,"openid");
	}
	public JsapiTicket signJsApiBySHA(String url) {
		Assert.notNullAndEmpty(url, ServiceCode.ERROR, "jsapi 签名时，url不能为空");
		String nonceStr = UUID.randomUUID().toString();
		String timestamp = Long.toString(System.currentTimeMillis() / 1000);
		String sbstr = new StringBuilder("jsapi_ticket=").append(getJsapi_ticket())
				.append("&noncestr=").append(nonceStr)
				.append("&timestamp=").append(timestamp)
				.append("&url=").append(url.split("#")[0]).toString();
		RemexConstants.logger.info("jsapi签名字符串为：" + sbstr);
		String signature = SHA1.SHA1(sbstr);
		RemexConstants.logger.info("jsapi签名为：" + signature);
		JsapiTicket ret = new JsapiTicket();
		ret.setAppId(config.getAppid());
		ret.setNonceStr(nonceStr);
		ret.setTimestamp(timestamp);
		ret.setSignature(signature);
		ret.setUrl(url);
		return ret;
	}
	public WeChatUserOpenIdList obtainOpenIdList(String openId) {
		return WeChatUtils.invokeApiReturnBean(this, "", WeChatUserOpenIdList.class, pulluserInfo, getAccess_token(), openId);
	}
	//-----------------------------------------------------//
	public String obtainStateRedirect(String state) {
		Assert.notNull(stateRedirects, ServiceCode.WEIXIN_CONFIG_ERROR, "没有为微信应用" + config.getAppid() + "配置具体的state_redirect参数。");
		String stateRedirect = stateRedirects.get(state);
//		Assert.notNullAndEmpty(stateRedirect, ServiceCode.WEIXIN_CONFIG_ERROR, "微信应用" + config.getAppid() + "的配置具体的state_redirect参数state=" + state + "配置为空");
		return Judgment.nullOrBlank(stateRedirect) ? state : stateRedirect;
	}
	public String obtainClickEventMsg(String eventKey) {
		Assert.notNull(wxClickEventMsgs, ServiceCode.WEIXIN_CONFIG_ERROR, "没有为微信应用" + config.getAppid() + "配置具体的菜单单击事件wxClickEventMsgs参数。");
		String clickEventMsg = wxClickEventMsgs.get(eventKey);
		Assert.notNullAndEmpty(clickEventMsg, ServiceCode.WEIXIN_CONFIG_ERROR, "微信应用" + config.getAppid() + "的配置具体的菜单单击事件wxClickEventMsgs参数eventKey=" + eventKey + "配置为空");
		return clickEventMsg;
	}
	public String obtainApiUrl(WeChatUtils.WeChatApi apiKey, String... args) {
		return String.format(WeChat.getApiUrl(config.getType(), apiKey), args);
	}

	//------------------------企业号-----------------------------//
	/* 企业号发送文本消息 */
	public WeChatMessageResult qyTextMsgSend(QyMsgTextData qyMsgData){
		return WeChatUtils.invokeApiReturnBean(this, JsonHelper.toJsonString(qyMsgData), WeChatMessageResult.class, send_msg, getAccess_token());
	}
	//-----------------------------------------------------//
	private WeChatWXBizMsgCrypt obtainWXBizMsgCrypt(){
		try {
			if(config.getType() == qy)
				return new cn.remex.wechat.utils.qy.aes.WXBizMsgCrypt(config.getToken(), config.getEncodingAESKey(), config.getAppid());
			else // if (type == mp) //默认为服务号
				return new cn.remex.wechat.utils.mp.aes.WXBizMsgCrypt(config.getToken(), config.getEncodingAESKey(), config.getAppid());
		} catch (Exception e) {
			throw new WeChatException(ServiceCode.WEIXIN_CONFIG_ERROR, e.getMessage(), e);
		}
	}
	public String encryptMsg(String replyMsg, String timeStamp, String nonce){
		try {
			if(Judgment.nullOrBlank(config.getEncodingAESKey())){
				return replyMsg;
			}else {
				return obtainWXBizMsgCrypt().encryptMsg(replyMsg, timeStamp, nonce);
			}
		} catch (Exception e) {
			throw new WeChatException(ServiceCode.WEIXIN_CONFIG_ERROR, "微信信息加密打包失败", e);
		}
	}
	public String decryptMsg(String msgSignature, String timeStamp, String nonce, String postData){
		try {
			if(Judgment.nullOrBlank(config.getEncodingAESKey())){
				if(postData.indexOf("<Encrypt>")>0){
					throw new WeChatException(ServiceCode.WEIXIN_CONFIG_ERROR, "微信服务为加密模式，需要配置wcaConfig.getEncodingAESKey()");
				}
				return postData;
			}else {
				return obtainWXBizMsgCrypt().decryptMsg(msgSignature, timeStamp, nonce, postData);
			}
		} catch (Exception e) {
			throw new WeChatException(ServiceCode.WEIXIN_CONFIG_ERROR, "微信信息解密打包失败", e);
		}
	}
	public String verifyURL(String msgSignature, String timeStamp, String nonce, String echoStr) {
		try {
			if(Judgment.nullOrBlank(config.getEncodingAESKey())){
				Assert.isTrue(SHA1.gen(config.getToken(), timeStamp, nonce).equals(msgSignature),ServiceCode.WEIXIN_CONFIG_ERROR,"不加密模式下的微信回调URL验证失败，msgSignature="+msgSignature+",timeStamp="+timeStamp+",nonce="+nonce+",echoStr="+echoStr);
				return echoStr;
			}else {
				return obtainWXBizMsgCrypt().verifyURL(msgSignature, timeStamp, nonce, echoStr);
			}
		} catch (Exception e) {
			throw new WeChatException(ServiceCode.WEIXIN_CONFIG_ERROR, "加密模式下的微信回调URL验证失败，msgSignature="+msgSignature+",timeStamp="+timeStamp+",nonce="+nonce+",echoStr="+echoStr, e);
		}
	}

	public WeChatAppConfig getConfig() {
		return config;
	}
}
